using System;
using System.Drawing;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Web.UI.WebControls;
using System.Web.UI;
using System.IO;

namespace Heckel.EasyTools.Diagramming
{
    public enum LineDirection
    {
        Undefined = -1,
        Up = 0,
        Down = 1
    }

    public enum DateInterval { Year, Month, Weekday, Day, Hour, Minute, Second }

    public static class Utils
    {
        public static MemoryStream MakeTransparentPixel()
        {
            Bitmap nBitmap = new Bitmap(1, 1);
            Graphics g = Graphics.FromImage(nBitmap);
            Pen p = new Pen(Color.Black);
            g.DrawRectangle(p, 0, 0, 1, 1);

            MemoryStream gstream = new MemoryStream();
            nBitmap.Save(gstream, ImageFormat.Gif);
            MemoryStream transparentStream = MakeTransparent(gstream, ImageFormat.Gif);

            return transparentStream;
        }

        public static MemoryStream MakeArrow(LineDirection d, int box, Color lineColor, LineDecoration deco, int lineWidth)
        {
            int squareSide = 14;
            if (lineWidth > 2)
                squareSide = squareSide + (lineWidth - 2) * (squareSide / 4);

            Bitmap nBitmap = new Bitmap(squareSide, squareSide);
            Graphics g = Graphics.FromImage(nBitmap);

            /*Point[] upoints = { new Point(0, 0), new Point(squareSide, 0), new Point(squareSide / 2, squareSide) };*/

            /*Point[] upoints = { new Point(0, 0), new Point(0, squareSide), new Point(squareSide, squareSide / 2) };
            Point[] dpoints = { new Point(0, squareSide), new Point(squareSide, squareSide), new Point(squareSide / 2, 0) };*/

            Point[] upoints = { new Point(0, 0), new Point(0, 0), new Point(0,0) };
            Point[] dpoints = { new Point(0, 0), new Point(0, 0), new Point(0,0) };

            SolidBrush b = new SolidBrush(lineColor);

            switch (d)
            {
                case LineDirection.Up:
                    g.FillPolygon(b, dpoints);
                    break;
                case LineDirection.Down:
                    g.FillPolygon(b, upoints);
                    break;
            }

            MemoryStream gstream = new MemoryStream();
            nBitmap.Save(gstream, ImageFormat.Gif);
            MemoryStream transparentStream = MakeTransparent(gstream, ImageFormat.Gif);

            return transparentStream;
        }

        public static MemoryStream MakeLine(LineDirection d, int box, Color lineColor, LineDecoration deco, int lineWidth)
        {
            Bitmap nBitmap = new Bitmap(box, box);
            Graphics g = Graphics.FromImage(nBitmap);
            Pen p = new Pen(lineColor);
            p.Width = (float)lineWidth;

            if (deco == LineDecoration.Dotted)
                p.DashStyle = DashStyle.Dot;
            else
                p.DashStyle = DashStyle.Solid;

            switch (d)
            {
                case LineDirection.Up:
                    g.DrawLine(p, box, 0, 0, box);
                    break;
                case LineDirection.Down:
                    g.DrawLine(p, 0, 0, box, box);
                    break;
            }

            MemoryStream gstream = new MemoryStream();
            nBitmap.Save(gstream, ImageFormat.Gif);
            MemoryStream transparentStream = MakeTransparent(gstream, ImageFormat.Gif);

            return transparentStream;
        }

        public static System.IO.MemoryStream MakeTransparent(System.IO.MemoryStream origBitmapMemoryStream, ImageFormat imagef)
        {
            Color transparentColor = Color.Black;
            int transparentArgb = transparentColor.ToArgb();
            using (Bitmap origBitmap = new Bitmap(origBitmapMemoryStream))
            {
                using (Bitmap newBitmap = new Bitmap(origBitmap.Width, origBitmap.Height, origBitmap.PixelFormat))
                {
                    ColorPalette origPalette = origBitmap.Palette;
                    ColorPalette newPalette = newBitmap.Palette;

                    int index = 0;
                    int transparentIndex = -1;

                    foreach (Color origColor in origPalette.Entries)
                    {
                        newPalette.Entries[index] = Color.FromArgb(255, origColor);
                        if (origColor.ToArgb() == transparentArgb) transparentIndex = index;
                        index += 1;
                    }

                    if (-1 == transparentIndex)
                    {
                        return origBitmapMemoryStream;
                    }

                    newPalette.Entries[transparentIndex] = Color.FromArgb(0, transparentColor);
                    newBitmap.Palette = newPalette;

                    Rectangle rect = new Rectangle(0, 0, origBitmap.Width, origBitmap.Height);

                    BitmapData origBitmapData = origBitmap.LockBits(rect, ImageLockMode.ReadOnly, origBitmap.PixelFormat);

                    BitmapData newBitmapData = newBitmap.LockBits(rect, ImageLockMode.WriteOnly, newBitmap.PixelFormat);

                    for (int y = 0; y < origBitmap.Height; y++)
                    {
                        for (int x = 0; x < origBitmap.Width; x++)
                        {
                            byte origBitmapByte = Marshal.ReadByte(origBitmapData.Scan0, origBitmapData.Stride * y + x);
                            Marshal.WriteByte(newBitmapData.Scan0, newBitmapData.Stride * y + x, origBitmapByte);
                        }
                    }

                    newBitmap.UnlockBits(newBitmapData);
                    origBitmap.UnlockBits(origBitmapData);

                    System.IO.MemoryStream nms = new System.IO.MemoryStream();
                    newBitmap.Save(nms, imagef);

                    return nms;
                }
            }
        }

        public static string HomeUrl
        {
            get
            {
                string host = System.Web.HttpContext.Current.Request.ServerVariables["SERVER_NAME"].ToString();
                string[] splitUrl = System.Web.HttpContext.Current.Request.Url.AbsoluteUri.Split('?');
                string url = splitUrl[0];

                string[] splitter = url.Split('/');
                string baseUrl = "";
                for (int u = 0; u < splitter.Length; u++)
                    if (u < 3)
                        baseUrl += splitter[u] + "/";

                //remove trailing /
                baseUrl = baseUrl.Substring(0, baseUrl.Length - 1);

                string[] getVD = System.Web.HttpContext.Current.Request.ServerVariables["PATH_INFO"].ToString().Split('/');
                string actVD = "";
                for (int v = 0; v < getVD.Length - 1; v++)
                    actVD += getVD[v] + "/";

                if (actVD != "")
                    actVD = actVD.Substring(0, actVD.Length - 1);

                baseUrl = baseUrl + actVD;

                return baseUrl;
            }
        }
        public static String ReverseString(String inStr)
        // Helper Method that reverses a String.
        {
            String outStr;
            int counter;
            outStr = "";
            for (counter = inStr.Length - 1; counter >= 0; counter--)
            {
                outStr = outStr + inStr[counter];
            }
            return outStr;
        }

        public static int HexToInt(String hexstr)
        // This method converts a hexvalues string as 80FF into a integer.
        // Note that you may not put a '#' at the beginning of string! There
        // is not much error checking in this method. If the string does not
        // represent a valid hexadecimal value it returns 0.
        {
            int counter, hexint;
            char[] hexarr;
            hexint = 0;
            hexstr = hexstr.ToUpper();
            hexarr = hexstr.ToCharArray();
            for (counter = hexarr.Length - 1; counter >= 0; counter--)
            {
                if ((hexarr[counter] >= '0') && (hexarr[counter] <= '9'))
                {
                    hexint += (hexarr[counter] - 48) * ((int)(Math.Pow(16, hexarr.Length - 1 - counter)));
                }
                else
                {
                    if ((hexarr[counter] >= 'A') && (hexarr[counter] <= 'F'))
                    {
                        hexint += (hexarr[counter] - 55) * ((int)(Math.Pow(16, hexarr.Length - 1 - counter)));
                    }
                    else
                    {
                        hexint = 0;
                        break;
                    }
                }
            }
            return hexint;
        }

        public static String IntToHex(int hexint)
        // This method converts a integer into a hexadecimal string representing the
        // int value. The returned string will look like this: 55FF. Note that there is
        // no leading '#' in the returned string! 
        {
            int counter, reminder;
            String hexstr;

            counter = 1;
            hexstr = "";
            while (hexint + 15 > Math.Pow(16, counter - 1))
            {
                reminder = (int)(hexint % Math.Pow(16, counter));
                reminder = (int)(reminder / Math.Pow(16, counter - 1));
                if (reminder <= 9)
                {
                    hexstr = hexstr + (char)(reminder + 48);
                }
                else
                {
                    hexstr = hexstr + (char)(reminder + 55);
                }
                hexint -= reminder;
                counter++;
            }
            return ReverseString(hexstr);
        }

        public static String IntToHex(int hexint, int length)
        // This version of the IntToHex method returns a hexadecimal string representing the
        // int value in the given minimum length. If the hexadecimal string is shorter then the
        // length parameter the missing characters will be filled up with leading zeroes.
        // Note that the returend string though is not truncated if the value exeeds the length!
        {
            String hexstr, ret;
            int counter;
            hexstr = IntToHex(hexint);
            ret = "";
            if (hexstr.Length < length)
            {
                for (counter = 0; counter < (length - hexstr.Length); counter++)
                {
                    ret = ret + "0";
                }
            }
            return ret + hexstr;
        }

        public static Color HexToColor(String hexString)
        // Translates a html hexadecimal definition of a color into a .NET Framework Color.
        // The input string must start with a '#' character and be followed by 6 hexadecimal
        // digits. The digits A-F are not case sensitive. If the conversion was not successfull
        // the color white will be returned.
        {
            Color actColor;
            int r, g, b;
            r = 0;
            g = 0;
            b = 0;
            if ((hexString.StartsWith("#")) && (hexString.Length == 7))
            {
                r = HexToInt(hexString.Substring(1, 2));
                g = HexToInt(hexString.Substring(3, 2));
                b = HexToInt(hexString.Substring(5, 2));
                actColor = Color.FromArgb(r, g, b);
            }
            else
            {
                actColor = Color.White;
            }
            return actColor;
        }

        public static String ColorToHex(Color actColor)
        // Translates a .NET Framework Color into a string containing the html hexadecimal 
        // representation of a color. The string has a leading '#' character that is followed 
        // by 6 hexadecimal digits. 
        {
            return "#" + IntToHex(actColor.R, 2) + IntToHex(actColor.G, 2) + IntToHex(actColor.B, 2);
        }

        public static Control RecursivelyFindControl(Control root, string id)
        {
            if (root.ID == id)
                return root;

            foreach (Control c in root.Controls)
            {
                Control t = RecursivelyFindControl(c, id);
                if (t != null)
                    return t;
            }

            return null;
        }

        public static void RecursivelyModifyWebControls(ref Control root, Type controlToFind, string eventToHandle, string eventText, string filterID)
        {
            if (root.GetType().Equals(controlToFind))
            {
                if (root.ID.IndexOf(filterID) > -1)
                    ((WebControl)root).Attributes.Add(eventToHandle, eventText);
            }

            for (int cx = 0; cx < root.Controls.Count; cx++)
            {
                Control c = root.Controls[cx];
                RecursivelyModifyWebControls(ref c, controlToFind, eventToHandle, eventText, filterID);
            }
        }

        public static void RecursivelyFindWebControls(Control root, Type controlToFind, string filterID, ref List<WebControl> finder)
        {
            if (root.GetType().Equals(controlToFind))
            {
                if (root.ID.IndexOf(filterID) > -1)
                    finder.Add((WebControl)root);
                else
                    finder.Add((WebControl)root);
            }

            for (int cx = 0; cx < root.Controls.Count; cx++)
            {
                Control c = root.Controls[cx];
                RecursivelyFindWebControls(c, controlToFind, filterID, ref finder);
            }
        }

        public static void RecursivelyFindAllWebControls(Control root, string filterID, ref List<WebControl> finder)
        {
            if (root.GetType().BaseType.Equals(typeof(WebControl)))
            {
                if (root.ID.IndexOf(filterID) > -1)
                    finder.Add((WebControl)root);
                else
                    finder.Add((WebControl)root);
            }

            for (int cx = 0; cx < root.Controls.Count; cx++)
            {
                Control c = root.Controls[cx];
                RecursivelyFindAllWebControls(c, filterID, ref finder);
            }
        }

        public static void RecursivelyFindAllTypesOfControl(Control root, Type controlToFind, ref List<Control> finder)
        {
            if (root.GetType().Equals(controlToFind))
                 finder.Add(root);

            for (int cx = 0; cx < root.Controls.Count; cx++)
            {
                Control c = root.Controls[cx];
                RecursivelyFindAllTypesOfControl(c, controlToFind, ref finder);
            }
        }

        public static Control RecursivelyFindTypeOfControl(Control root, Type controlToFind, int currentIndex, int instance)
        {
            if (root.GetType().Equals(controlToFind))
            {
                currentIndex++;
                if (currentIndex == instance)
                    return root;
            }

            foreach (Control c in root.Controls)
            {
                Control t = RecursivelyFindTypeOfControl(c, controlToFind, currentIndex, instance);
                if (t != null)
                    return t;
            }

            return null;
        }

        public static bool DoStringsResembleEachOther(string stringToSplit, string stringToCheck, int threshold)
        {
            char[] allChars = stringToSplit.ToCharArray();
            List<string> groupings = new List<string>();
            int grouper = -1;
            int sIndex = -1;
            foreach (char cx in allChars)
            {
                grouper++;
                if (grouper % threshold == 0)
                {
                    grouper = 0;
                    groupings.Add("");
                    sIndex++;
                }
                groupings[sIndex] += cx.ToString().ToLower();
            }

            foreach (string gr in groupings)
            {
                if (gr.Length == threshold)
                {
                    if (stringToCheck.ToLower().IndexOf(gr) > -1)
                        return true;
                }
            }

            return false;
        }


        public static string StripHTML(string inputString)
        {
            string HTML_TAG_PATTERN = "<.*?>";

            string stripHTML = Regex.Replace
              (inputString, HTML_TAG_PATTERN, string.Empty);

            stripHTML = stripHTML.Replace("&nbsp;", "");

            return stripHTML;
        }

        public static double DateDiff(DateInterval interval, DateTime date1, DateTime date2)
        {
            TimeSpan ts = ts = date2 - date1;
            switch (interval)
            {
                case DateInterval.Year:
                    return date2.Year - date1.Year;
                case DateInterval.Month:
                    return (date2.Month - date1.Month) + (12 * (date2.Year - date1.Year));
                case DateInterval.Weekday:
                    return Fix(ts.TotalDays) / 7;
                case DateInterval.Day:
                    return ts.TotalDays;
                case DateInterval.Hour:
                    return ts.TotalHours;
                case DateInterval.Minute:
                    return ts.TotalMinutes;
                default:
                    return ts.TotalSeconds;
            }
        }

        private static long Fix(double Number)
        {
            if (Number >= 0)
            {
                return (long)Math.Floor(Number);
            }
            return (long)Math.Ceiling(Number);
        }
    }
}
